package me.zhengjie.modules.business.service.impl;

import cn.hutool.json.JSONUtil;
import lombok.Synchronized;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.business.domain.Question;
import me.zhengjie.modules.business.domain.WxUser;
import me.zhengjie.modules.business.repository.WxUserRepository;
import me.zhengjie.modules.business.util.ChatRedisUtil;
import me.zhengjie.modules.business.util.ImageUtil;
import me.zhengjie.utils.*;
import me.zhengjie.modules.business.repository.QuestionRepository;
import me.zhengjie.modules.business.service.QuestionService;
import me.zhengjie.modules.business.service.dto.QuestionDto;
import me.zhengjie.modules.business.service.dto.QuestionQueryCriteria;
import me.zhengjie.modules.business.service.mapper.QuestionMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
// 默认不使用缓存
//import org.springframework.cache.annotation.CacheConfig;
//import org.springframework.cache.annotation.CacheEvict;
//import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.sql.Timestamp;
import java.util.*;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;

/**
 * @author churuitao
 * @date 2020-02-02
 */
@Service
//@CacheConfig(cacheNames = "question")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class QuestionServiceImpl implements QuestionService {

    private final QuestionRepository questionRepository;

    private final QuestionMapper questionMapper;

    @Autowired
    private WxUserRepository wxUserRepository;

    /**
     * 配置文件上传路径
     */
    @Value("${file.avatar}")
    private String avatar;

    public QuestionServiceImpl ( QuestionRepository questionRepository, QuestionMapper questionMapper ) {
        this.questionRepository = questionRepository;
        this.questionMapper = questionMapper;
    }


    @Override
    //@Cacheable
    public Map<String, Object> queryAll ( QuestionQueryCriteria criteria, Pageable pageable ) {
        Page<Question> page = questionRepository.findAll(( root, criteriaQuery, criteriaBuilder ) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable);
        return PageUtil.toPage(page.map(questionMapper::toDto));
    }

    @Override
    //@Cacheable
    public List<QuestionDto> queryAll ( QuestionQueryCriteria criteria ) {
        return questionMapper.toDto(questionRepository.findAll(( root, criteriaQuery, criteriaBuilder ) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder)));
    }

    @Override
    //@Cacheable(key = "#p0")
    public QuestionDto findById ( Integer id ) {
        Question question = questionRepository.findById(id).orElseGet(Question::new);
        ValidationUtil.isNull(question.getId(), "Question", "id", id);
        return questionMapper.toDto(question);
    }

    @Override
    //@CacheEvict(allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    public QuestionDto create ( Question resources ) {
        return questionMapper.toDto(questionRepository.save(resources));
    }

    @Override
    //@CacheEvict(allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    public void update ( Question resources ) {
        Question question = questionRepository.findById(resources.getId()).orElseGet(Question::new);
        ValidationUtil.isNull(question.getId(), "Question", "id", resources.getId());
        question.copy(resources);
        questionRepository.save(question);
    }

    @Override
    //@CacheEvict(allEntries = true)
    public void deleteAll ( Integer[] ids ) {
        for (Integer id : ids) {
            questionRepository.deleteById(id);
        }
    }

    @Override
    public void download ( List<QuestionDto> all, HttpServletResponse response ) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (QuestionDto question : all) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("提问方", question.getAskId());
            map.put("解答方", question.getAnswerId());
            map.put("图片路径", question.getPicturePath());
            map.put("问题状态", question.getStatus());
            map.put("隐藏", question.getHidden());
            map.put("创建日期", question.getCreateTime());
            map.put("问题标题", question.getTitle());
            map.put("问题类型", question.getQuestionType());
            map.put("聊天内容", question.getContext());
            map.put("解答时间", question.getUpdateTime());
            map.put("解决时间", question.getSolveTime());
            map.put("开始解答时间", question.getBeginAnswerTime());
            list.add(map);
        }
        me.zhengjie.utils.FileUtil.downloadExcel(list, response);
    }

    @Override
    public Map countQuestion ( Integer id, Integer type ) {
        Map<String, Object> map = new HashMap<>();
        if (type == 0) {
            map.put("askCount", questionRepository.countByAskId(id));
            map.put("solveCount", questionRepository.countByAskIdAndStatus(id, 2));
        } else if (type == 1) {
            map.put("answerCount", questionRepository.countByAnswerId(id));
            map.put("solveCount", questionRepository.countByAnswerIdAndStatus(id, 2));
        }
        return map;
    }

    @Override
    public QuestionDto getQuestionById ( Integer questionId ) {
        Question question = questionRepository.findById(questionId).orElseGet(Question::new);
        WxUser askUser = wxUserRepository.findById(question.getAskId()).orElseGet(WxUser::new);
        WxUser answerUser = null;
        if (question.getAnswerId() != null) {
            answerUser = wxUserRepository.findById(question.getAnswerId()).orElseGet(WxUser::new);
        }
        return questionMapper.from(question, askUser, answerUser);
    }

    @Override
    public QuestionDto insertAndPicture ( Question resources, MultipartFile multipartFile ) {
        String[] imageTypeArr = {"jpg", "png"};
        //如果文件是图片类型
        if (ImageUtil.verifyFileType(multipartFile, imageTypeArr)) {
            File file = me.zhengjie.utils.FileUtil.upload(multipartFile, avatar);
            if (file == null) {
                throw new BadRequestException("上传的文件不能为空");
            }
            Question question = new Question();
            question.setPicturePath(file.getPath());
            //数据库存储信息
            return create(resources);
        } else {
            throw new BadRequestException("请上传图片类型的文件");
        }

    }

    @Override
    @Synchronized
    public boolean rushThisQuestion ( Integer questionId, Integer answerId ) {
        Question question = questionRepository.findById(questionId).orElseGet(Question::new);
        if (question.getStatus() == 0) {
            question.setStatus(1);
            question.setAnswerId(answerId);
            question.setBeginAnswerTime(new Timestamp(System.currentTimeMillis()));
            questionRepository.save(question);
            return true;
        }
        return false;
    }

    @Override
    public void updateSolving ( Integer questionId, Integer answerId ) {
        Question question = questionRepository.findById(questionId).orElseGet(Question::new);
        ValidationUtil.isNull(question.getId(), "Question", "id", questionId);
        question.setAnswerId(answerId);
        question.setBeginAnswerTime(new Timestamp(System.currentTimeMillis()));
        question.setStatus(1);
        questionRepository.save(question);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateChatContent ( Integer questionId, Integer askId, Integer answerId ) {
        //实例化对象，从bean中取出  （还不理解）
        ChatRedisUtil chatRedisUtil = SpringContextHolder.getBean(ChatRedisUtil.class);
        //将用户未收到的消息，进行签证

        //将askId和answerId拼接成key，即房间号
        String key = chatRedisUtil.createChatNumber(questionId, askId, answerId);
        //得到缓存中的聊天信息的json字符串
        String chatContent = getChatContent(questionId, askId, answerId);
        //将数据存进数据库
        Question oldQuestion = questionRepository.findById(questionId).orElseGet(Question::new);
        ValidationUtil.isNull(oldQuestion.getId(), "Question", "id", questionId);
        oldQuestion.setContext(chatContent);
        //设置问题状态为已解答
        oldQuestion.setStatus(2);
        oldQuestion.setSolveTime(new Timestamp(System.currentTimeMillis()));
        Question newQuestion = questionRepository.save(oldQuestion);
        if (newQuestion.getId() > 0) {
            //清除redis中缓存的数据
            chatRedisUtil.deleteCacheChatMessage(key);
        }
    }

    @Override
    public String getChatContent ( Integer questionId, Integer askId, Integer answerId) {
        //实例化对象，从bean中取出  （还不理解）
        ChatRedisUtil chatRedisUtil = SpringContextHolder.getBean(ChatRedisUtil.class);
        //将askId和answerId拼接成key，即房间号
        String key = chatRedisUtil.createChatNumber(questionId, askId, answerId);
        List<Object> chatList = chatRedisUtil.getCacheChatMessage(key);
        //将List数据转为json字符串，返回
        return JSONUtil.toJsonStr(chatList);
    }


}